package com.xzy.sms.web.system.service.security;

import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;

import com.google.common.collect.Lists;
import com.xzy.sms.web.domain.entity.User;
import com.xzy.sms.web.domain.service.UserService;
import com.xzy.sms.web.system.PermissionConstants;
import com.xzy.sms.web.system.service.PermService;
import com.xzy.sms.web.system.utils.PermUtils;
import com.xzyframework.SpringContextHolder;
import com.xzyframework.security.uitls.Passwords;
import com.xzyframework.utils.Encodes;

/**
 * @desc 登录权限验证
 * @author wjw
 * @time 2017年11月16日上午10:35:23
 */
public class ShiroRealm extends AuthorizingRealm {
    
    /** 用户服务类 */
    protected UserService userService;
    
    /** 权限服务类 */
    protected PermService permissionService;
    
    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        AuthenticationInfo info = null;
        
        //用户与密码登陆的token
    	UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        // 查询指定用户
    	String username = token.getUsername();
    	User user = getUserService().findByAccount(username);
        if(user!=null){
        	 String password = user.getPassword();
             if (StringUtils.isEmpty(password)) {
                 throw new IncorrectCredentialsException("密码格式错误.");
             }
             byte[] salt = Encodes.decodeHex(password.substring(0, 16));
             UserProfile profile = new UserProfile(user.getUserId(), user.getAccount(), user.getName());
             info = new SimpleAuthenticationInfo(profile, password.substring(16), ByteSource.Util.bytes(salt), getName());
		}else{
			throw new UnknownAccountException("帐号不存在");
		}
        return info;
    }
    
    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        UserProfile profile = (UserProfile) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<String> roles = Lists.newArrayList();
        info.addRoles(roles);
        
        String account = profile.getAccount();
        if ("admin".equals(account) || "superadmin".equals(account)) {
            // 超管
            info.addStringPermissions(PermUtils.getAllPermStrs());
            info.addStringPermission(PermissionConstants.ADMIN);
        } else {
            String userId = profile.getUserId();
            info.addStringPermissions(getPermService().findPermStrsByUserId(userId));
            info.addStringPermission(PermissionConstants.USER);
        }
        
        return info;
    }
    
    /**
     * 设定Password校验的Hash算法与迭代次数.
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(Passwords.HASH_ALGORITHM);
        matcher.setHashIterations(Passwords.HASH_INTERATIONS);
        setCredentialsMatcher(matcher);
    }
    
    /**
     * 清空用户关联权限认证，待下次使用时重新加载
     * 
     * @param principal principal
     */
    public void clearCachedAuthorizationInfo(String principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
        clearCachedAuthorizationInfo(principals);
    }
    
    /**
     * 清空所有关联认证
     */
    public void clearAllCachedAuthorizationInfo() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache != null) {
            for (Object key : cache.keys()) {
                cache.remove(key);
            }
        }
    }
    
    /**
     * @param userService 要设置的 userService
     */
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    /**
     * @return userService
     */
    public UserService getUserService() {
        if (userService == null) {
            userService = SpringContextHolder.getBean(UserService.class);
        }
        return userService;
    }
    
    /**
     * @return PermissionService
     */
    public PermService getPermService() {
        if (permissionService == null) {
            permissionService = SpringContextHolder.getBean(PermService.class);
        }
        return permissionService;
    }
}
